import json
import os
from typing import Dict, List, Tuple

from src import graphics
from src.graphics import truncate_two_decimal_places
from src.rating import calculate_rating, calculate_rating_by_score


def load_json(csv_output_path: str = 'score/lum_b30.csv',
              json_input_path: str = 'score/rating.json') -> Dict:
    """
    从JSON文件加载Rating数据,更新音乐数据库,并保存Rating信息到CSV文件
    
    Args:
        csv_output_path: CSV输出文件路径
        json_input_path: JSON输入文件路径
        
    Returns:
        dict: 从JSON加载的Rating数据
        
    Raises:
        FileNotFoundError: 如果JSON输入文件不存在
        json.JSONDecodeError: 如果JSON解析出错
    """
    music_path = 'assets/music.json'

    # 加载Rating数据
    with open(json_input_path, 'r', encoding='utf-8') as f:
        rating = json.load(f)

    # 保存Rating信息到CSV
    _save_rating_to_csv(rating['data']['base_rating_list'], csv_output_path)

    # 更新音乐数据库
    _update_music_database(rating['data'], music_path)

    return rating


def load_csv(csv_path: str) -> Tuple[List[Dict], float]:
    """
    从CSV文件加载Rating数据并计算Rating值
    
    Args:
        csv_path: CSV文件路径
        
    Returns:
        tuple: (最佳30个成绩列表, 平均Rating值)
        
    Raises:
        FileNotFoundError: 如果music.json文件不存在
        json.JSONDecodeError: 如果JSON解析出错
    """
    # 加载音乐数据
    with open('assets/music.json', 'r', encoding='utf-8') as f:
        music = json.load(f)

    # 读取CSV数据
    with open(csv_path, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    # 解析并处理成绩数据
    rating_list = _process_csv_scores(lines[1:], music)

    # 排序并截取前30个成绩
    rating_list.sort(
        key=lambda x: (calculate_rating(x['constant'], int(x['score'])), x['score']),
        reverse=True
    )
    rating_list = rating_list[:30]

    # 计算平均Rating
    avg_rating = truncate_two_decimal_places(
        sum([x['rating'] / 100 for x in rating_list]) / len(rating_list)
    )

    return rating_list, avg_rating


def save_to_csv(csv_path: str, rating: List[Dict]):
    """
    保存Rating数据到CSV文件
    
    Args:
        csv_path: CSV文件路径
        rating: Rating数据列表
    """
    with open(csv_path, 'w', encoding='utf-8') as f:
        f.write('song,difficulty,score,rating\n')
        for song in rating:
            f.write(
                f"{song['music']['name']},"
                f"{song['difficulty']},"
                f"{song['score']},"
                f"{round(song['rating']) / 100}\n"
            )


def _save_rating_to_csv(rating_list: List[Dict], csv_path: str):
    """
    保存Rating列表到CSV文件
    
    Args:
        rating_list: Rating数据列表
        csv_path: CSV文件路径
    """
    with open(csv_path, 'w', encoding='utf-8') as f:
        f.write('song,difficulty,score,rating\n')
        for song in rating_list:
            f.write(
                f"{song['music']['name']},"
                f"{graphics.difficulty_mapping_up[song['difficulty']]},"
                f"{song['score']},"
                f"{song['rating'] / 100}\n"
            )


def _update_music_database(rating_data: Dict, music_path: str):
    """
    更新音乐数据库
    
    Args:
        rating_data: Rating数据
        music_path: 音乐数据库文件路径
    """
    # 如果music.json不存在则创建空字典
    if not os.path.exists(music_path):
        music = {}
    else:
        with open(music_path, 'r', encoding='utf-8') as f:
            music = json.load(f)

    # 合并所有成绩列表
    all_scores = (
            rating_data['base_rating_list'] +
            rating_data['hot_rating_list'] +
            rating_data['next_rating_list']
    )

    # 更新音乐数据
    for song in all_scores:
        difficulty = graphics.difficulty_mapping_up[song['difficulty']]
        if song['music']['name'] not in music:
            music[song['music']['name']] = {
                'jacket': song['music']['jacket'],
                difficulty: calculate_rating_by_score(song['score'], song['rating'] / 100),
                'artist': song['music']['artist'],
            }
        else:
            music[song['music']['name']][difficulty] = (
                calculate_rating_by_score(song['score'], song['rating'] / 100)
            )

    # 保存更新后的数据库
    with open(music_path, 'w', encoding='utf-8') as f:
        json.dump(music, f, ensure_ascii=False, indent=4)


def _process_csv_scores(lines: List[str], music: Dict) -> List[Dict]:
    """
    处理CSV文件中的成绩数据
    
    Args:
        lines: CSV文件内容行
        music: 音乐数据字典
        
    Returns:
        list: 处理后的成绩数据列表
    """
    rating_list = []
    for line in lines:
        song, difficulty, score, rating = line.strip().split(',')

        # 获取歌曲定数
        if song not in music:
            constant = 0
            print(f"ALERT: {song} not in music.json")
        elif difficulty not in music[song]:
            constant = 0
            print(f"ALERT: {difficulty} not in {song}")
        else:
            constant = music[song][difficulty]

        # 构建成绩数据
        rating_list.append({
            'music': {
                'name': song,
                'jacket': music[song]['jacket'],
                'artist': music[song]['artist'],
            },
            'difficulty': difficulty,
            'score': int(score),
            'constant': constant,
            'rating': truncate_two_decimal_places(
                calculate_rating(constant, int(score))
            ) * 100,
        })

    return rating_list
